package com.dgut.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dgut.app.service.BillService;
import com.dgut.common.dto.BillDTO;
import com.dgut.common.dto.RemarkDTO;
import com.dgut.common.entity.Bill;
import com.dgut.common.entity.Remark;
import com.dgut.common.entity.WxUser;
import com.dgut.common.enums.BillTypeEnum;
import com.dgut.common.mapper.BillMapper;
import com.dgut.common.mapper.RemarkMapper;
import com.dgut.common.utils.ApiException;
import com.dgut.common.utils.DateUtils;
import com.dgut.common.utils.JwtUtil;
import com.dgut.common.vo.BillCalendarVO;
import com.dgut.common.vo.BillDetailVO;
import com.dgut.common.vo.BillTagDataVO;
import com.dgut.common.vo.BillVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author IT00ZYQ
 * @date 2021/4/13 15:20
 **/
@Service
@Slf4j
public class BillServiceImpl implements BillService {

    private final BillMapper billMapper;
    private final RemarkMapper remarkMapper;
    public BillServiceImpl(BillMapper billMapper, RemarkMapper remarkMapper) {
        this.billMapper = billMapper;
        this.remarkMapper = remarkMapper;
    }

    @Override
    public void addBill(BillDTO dto, String token) {
        WxUser user = JwtUtil.getUser(token);
        billMapper.insert(Bill.builder()
                .actualDate(dto.getDate())
                .money(dto.getMoney())
                .tagId(dto.getTagId())
                .title(dto.getTitle())
                .type(dto.getType())
                .userId(user.getId())
                .build());
    }

    @Override
    public void deletedBill(Integer id) {
        // 删除账单
        billMapper.deleteById(id);
    }

    @Override
    public BillDetailVO billDetail(Date begin, Date end, String token) {
        WxUser user = JwtUtil.getUser(token);
        // 支出饼状图
        List<BillTagDataVO> spendingList = billMapper.listBillTag(begin, end, user.getId(), BillTypeEnum.SPENDING.getCode());
        BigDecimal spendingSum = spendingList.stream().map(BillTagDataVO::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        for (BillTagDataVO vo : spendingList) {
            vo.setRate(vo.getMoney().divide(spendingSum, 2, RoundingMode.HALF_UP));
        }
        // 收入饼状图
        List<BillTagDataVO> incomeList = billMapper.listBillTag(begin, end, user.getId(), BillTypeEnum.INCOME.getCode());
        BigDecimal incomeSum = incomeList.stream().map(BillTagDataVO::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        for (BillTagDataVO vo : incomeList) {
            vo.setRate(vo.getMoney().divide(incomeSum, 2, RoundingMode.HALF_UP));
        }

        // 支出列表
        List<BillVO> sList = billMapper.listBill(begin, end, user.getId(), BillTypeEnum.SPENDING.getCode());
        // 收入列表
        List<BillVO> iList = billMapper.listBill(begin, end, user.getId(), BillTypeEnum.INCOME.getCode());

        Remark remark = null;
        // 请求的是一天的账单，返回备注字段
        if (DateUtils.sameDate(begin, end)) {
            remark = remarkMapper.selectByDate(begin, user.getId());
        }

        return BillDetailVO.builder()
                .income(incomeList)
                .spending(spendingList)
                .incomeList(iList)
                .spendingList(sList)
                .totalIncome(iList.stream().map(BillVO::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add))
                .totalSending(sList.stream().map(BillVO::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add))
                .remark(remark != null ? remark.getContent():null)
                .build();
    }

    @Override
    public void addRemark(RemarkDTO dto, String token) {
        WxUser user = JwtUtil.getUser(token);
        Remark remark = remarkMapper.selectByDate(dto.getDate(), user.getId());
        if (remark != null) {
            remark.setContent(dto.getRemark());
            remarkMapper.updateById(remark);
        } else {
            remarkMapper.insert(Remark.builder()
                    .content(dto.getRemark())
                    .remarkDate(dto.getDate())
                    .userId(user.getId())
                    .build());
        }
    }

    @Override
    public void updateRemark(RemarkDTO dto, String token) {
        WxUser user = JwtUtil.getUser(token);
        Remark remark = remarkMapper.selectByDate(dto.getDate(), user.getId());
        if (remark == null) {
            throw new ApiException("备注信息不存在");
        }
        remark.setContent(dto.getRemark());
        remarkMapper.updateById(remark);
    }

    @Override
    @SuppressWarnings("all")
    public List<BillCalendarVO> billCalendar(Date date, String token) {
        WxUser user = JwtUtil.getUser(token);
        Date first = DateUtils.firstDateOfMonth(date);
        Date last = DateUtils.lastDateOfMonth(date);

        // 查询该用户指定月份所有日期的备注信息
        QueryWrapper<Remark> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", user.getId()).between("remark_date", first, last);
        Map<Date, String> map = remarkMapper.selectList(wrapper).stream().collect(Collectors.toMap(e -> DateUtils.getFirstTimeOfDay(e.getRemarkDate()), Remark::getContent));

        // 构造日历信息
        List<BillCalendarVO> list = new ArrayList<>();
        for (Date d : DateUtils.getDateList(first, last)) {
            list.add(BillCalendarVO.builder()
                    .date(d)
                    .number(d.getDate())
                    .remark(map.get(d))
                    .build());
        }

        return list;
    }
}
